package gnss_plugs

import (
	"dgo/goutils/gnss"
	"dgo/goutils/utils"
	"fmt"
	"io"
	"sync/atomic"
	"time"
)

const (
	VRS_PACK_PRE_BYTE byte = 0xEA
)

type GnssRtcmVrsWriter struct {
	Id         string
	MountPoint string
	Sys        byte
	bodyCnt    int

	epochBufPack  utils.BytesBuilder
	lastObsTime   time.Time
	dataWriter    io.Writer
	RtcmWriteType int // 0: 所有的, 1: obs, 2:eph

	rtcmQueue *utils.QueueTask

	// 检测系统重入bug
	lastgid          uint64
	checkworkingflag int32
	lastdebuginfo    string
	DebuginfoFunc    func() string

	lastwrite_flag     int32
	lastwrite_currTime time.Time
	lastwrite_filename string
	lastwrite_T        time.Time // 最后Writer时间
	write_size         int64
	lastwrite_goid     uint64
	lastwrite_errmsg   string

	lastrecv_gnss_t    time.Time
	lastrecv_matched_t time.Time
}

func NewGnssRtcmVrsWriter() *GnssRtcmVrsWriter {
	rval := &GnssRtcmVrsWriter{
		Id:        utils.RandKeyString(4),
		rtcmQueue: utils.NewQueueTaskFunc(),
	}
	rval.rtcmQueue.ConfigMaxQueueSize(1024)
	rval.rtcmQueue.ConfigIntervalCallBack(time.Millisecond*500, rval.onRtcmTaskQueue).Start()
	return rval
}

func (this *GnssRtcmVrsWriter) RangeStatus(cb func(caption string, val interface{}) bool) {
	if cb == nil {
		return
	}

	if !cb("lastrecv_gnss_t", this.lastrecv_gnss_t) {
		return
	}

	if !cb("lastrecv_matched_t", this.lastrecv_matched_t) {
		return
	}

	if !cb("write_size", this.write_size) {
		return
	}

	if !cb("lastwrite_t", this.lastwrite_T) {
		return
	}

	if !cb("lastwrite_errmsg", this.lastwrite_errmsg) {
		return
	}

	if !cb("rtcm_queue_size", this.rtcmQueue.Count()) {
		return
	}
}

func (this *GnssRtcmVrsWriter) onRtcmTaskQueue() {
	if this.rtcmQueue.Count() == 0 {
		return
	}
	var bufPack utils.BytesBuilder
	bufPack.Reset()
	bufPack.WriteByte(VRS_PACK_PRE_BYTE)                   // 引导符
	bufPack.WriteUInt16_BE(0)                              // 长度占位符
	bufPack.AppendFixedStrWithZeroByte(this.MountPoint, 4) // 4位源节点长度
	w, _ := gnss.Time2GpsT(time.Now())
	bufPack.WriteUInt16_BE(uint16(w)) // GPS周
	n := 0

	maxN := 10
	//if this.RtcmWriteType == 2 { // 星历
	//	maxN = 1
	//}

	// 打包可能不止一个RTCM-BUF
	if this.rtcmQueue.PopTaskArgMaxFunc(maxN, func(args ...interface{}) bool {
		tmpBuf := args[0].([]byte)
		bufPack.Write(tmpBuf)
		n += len(tmpBuf)
		return true
	}) > 0 {
		l := bufPack.Len() - 3                 // 4Mountpoint + WN(2) + RTCM
		bufPack.ReplaceUInt16_BE(1, uint16(l)) // 替换长度
		crc24 := utils.CRC24QBuf(bufPack.Bytes())
		bufPack.WriteUInt32_BE(uint32(crc24)) // crc24
		n, err := this.dataWriter.Write(bufPack.Bytes())
		if err != nil {
			this.lastwrite_errmsg = fmt.Sprintf("[%s]观测值写入异常:%s", utils.NowString(), err.Error())
		}
		this.lastwrite_T = time.Now()
		this.write_size += int64(n)
	}

}

func (this *GnssRtcmVrsWriter) checkBegin(t1 time.Time) {
	if this.lastObsTime.IsZero() {
		this.epochBufPack.Reset()
		this.epochBufPack.WriteByte(VRS_PACK_PRE_BYTE)                   // 引导符
		this.epochBufPack.WriteUInt16_BE(0)                              // 长度占位符
		this.epochBufPack.AppendFixedStrWithZeroByte(this.MountPoint, 4) // 4位源节点长度
		//mbuf := make([]byte, 4)
		//srcBuf := []byte(this.MountPoint);
		//copy(mbuf, srcBuf[:4]);
		//this.epochBufPack = append(this.epochBufPack, mbuf...);
		w, _ := gnss.Time2GpsT(t1)
		//binary.BigEndian.PutUint16(mbuf, uint16(w));
		//this.epochBufPack = append(this.epochBufPack, mbuf[:2]...);
		this.epochBufPack.WriteUInt16_BE(uint16(w)) // GPS周

		this.lastObsTime = t1
	}
}

func (this *GnssRtcmVrsWriter) SetWriter(w io.Writer) {
	this.dataWriter = w
}

func (this *GnssRtcmVrsWriter) checkObsEnd() {
	if !this.lastObsTime.IsZero() {
		if this.dataWriter != nil {
			l := this.epochBufPack.Len() - 3                 // 4Mountpoint + WN(2) + RTCM
			this.epochBufPack.ReplaceUInt16_BE(1, uint16(l)) // 替换长度
			crc24 := utils.CRC24QBuf(this.epochBufPack.Bytes())
			this.epochBufPack.WriteUInt32_BE(uint32(crc24)) // crc24
			n, err := this.dataWriter.Write(this.epochBufPack.Bytes())
			if err != nil {
				this.lastwrite_errmsg = fmt.Sprintf("[%s]观测值写入异常:%s", utils.NowString(), err.Error())
			}
			this.lastwrite_T = time.Now()
			this.write_size += int64(n)

			//utils.Log.InfoTypef("data", "t1: %s, crc24:%d, rtcmlen:%d, buf:%s\r\n", utils.DateTimeString2(this.lastObsTime), crc24, l, this.epochBufPack.HexString(""))
		}
		this.lastObsTime = utils.ZeroTime
	}

	this.bodyCnt = 0
}

func (this *GnssRtcmVrsWriter) Stop() {
	this.checkObsEnd()
}

func (this *GnssRtcmVrsWriter) OnRecvGnssRecCallBack(sender interface{}, channelid string, subscribeid interface{}, data interface{}, tag interface{}, isBreak *bool) bool {
	this.lastrecv_gnss_t = time.Now()
	if atomic.CompareAndSwapInt32(&this.checkworkingflag, 0, 1) {
		this.lastgid = utils.GetCurrentGoRoutineID()
		if this.DebuginfoFunc != nil {
			this.lastdebuginfo = this.DebuginfoFunc()
		}
		defer func() {
			this.checkworkingflag = 0
		}()
		if rtcmBuf, ok := data.([]byte); ok { //  rtcmBuf
			msgid := gnss.GetRtcmMsgId(rtcmBuf, 24)
			isObsMsm := gnss.RtcmIsObsMsm(msgid)
			if isObsMsm && (this.RtcmWriteType == 0 || this.RtcmWriteType == 1) {
				delaysecs := time.Now().Sub(this.lastrecv_matched_t).Seconds()
				if (!this.lastrecv_matched_t.IsZero()) && (delaysecs > 5) {
					utils.Log.WarnTypef("DELAY", "[%s]延迟[%.2f]s,timestamp:%d->%d", this.MountPoint, delaysecs, this.lastrecv_matched_t.Unix(), time.Now().Unix())
				}
				this.lastrecv_matched_t = time.Now()
				syncflag := gnss.GetRtcmMsmSynchronousFlag(rtcmBuf, 24)
				navisys := gnss.GetNaviSysFromMsgId(msgid)
				t1 := gnss.DecodeRtcmBufTime(rtcmBuf, 24, navisys, utils.ZeroTime)
				this.checkBegin(t1)
				this.epochBufPack.Write(rtcmBuf)
				this.bodyCnt++
				if syncflag == 0 || t1 != this.lastObsTime {
					// fmt.Printf("--END(PACK:%d)--%s %d\r\n\n", this.epochBufPack.Len(), utils.DateTimeString2(t1), msgid);
					this.checkObsEnd()
				} else {
					// fmt.Printf("  --%s %d\r\n", utils.DateTimeString2(t1), msgid)
				}
			} else if gnss.RtcmIsEph(msgid) && (this.RtcmWriteType == 0 || this.RtcmWriteType == 2) {
				this.lastrecv_matched_t = time.Now()
				err := this.rtcmQueue.Push(rtcmBuf)
				if err != nil {
					utils.Log.WarnTypef("EPH", "压入rtcmQueue异常:%s", err.Error())
				}
				//fmt.Printf("%d %s\r\n", msgid, utils.BufToHexStr(rtcmBuf, 0, ""))
			}
		}

		return true
	} else {
		lastid := this.lastgid
		curr_gid := utils.GetCurrentGoRoutineID()
		debuginfo := "[需要设定debuginfofunc,进行获取信息]"
		if this.DebuginfoFunc != nil {
			debuginfo = this.DebuginfoFunc()
		}
		str := fmt.Sprintf("[并发重入]%s(%s), current_gid:%d\r\n debuginfo:%s\r\n "+"==============\r\n"+
			"lastgid:%d\r\n lastdebuginfo:%s\r\n", this.Id, this.MountPoint,
			curr_gid, debuginfo,
			lastid, this.lastdebuginfo)
		utils.Log.WarnTypef("GNSS-BUG", str)
		return false
	}
}
